home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
AGA Toolkit '97
/
The AGA Toolkit '97.iso
/
miscellaneous
/
hardware
/
pckeybhack
/
onlyat.asm
next >
Wrap
Assembly Source File
|
1996-09-07
|
25KB
|
790 lines
;* these port equates are explained below. Relocate them to any of
;* Port1, pins 0-7 or Port3, pins 0-7, except Port3, pins2 and 3
;* because these are the external interrupts.
;* it doesn't matter as long as you equate the right pin to the right
;* signal.
.equ Kclk,p1.0
.equ Kdat,p1.1
.equ Aclk,p1.3
.equ Adat,p1.4
.equ Areset,p1.5
.org 0000h
init: ljmp start
.org 001bh
ljmp timer1int
;**************************************************
;*
;*
;* Equates Descriptions:
;*
;* Aclk is the line to the Amiga keyboard clock in. (P1.3)
;* Adat is the line to the Amiga keyboard data in. (P1.4)
;* Areset is the Amiga Reset line (P1.5) (for the A500)
;* Kclk is the line to the Keyboard clock out (P1.0)
;* Kdat is the line to the Keyboard data out (P1.1)
;*
;* Oldchar is the last character typed to go to the Amiga.
;* This is used to tell if the Capslock was Pressed and
;* Released without pressing any other keys. If this was done,
;* then it is a "Caps Lock" otherwise, the Caps key functions
;* as the Control Key because of the keyboard remapping.
;*
;* Capbit is the flag which tells whether the Caps Lock
;* should be down or up.
;* Capdown is the flag which tells whether the Caps Lock
;* KEY is presently down or up. The difference between Capdown
;* and Capbit is that Capdown relates to the KEY. Capbit toggles
;* once for every "press and release" of the Cap Lock Key.
;* Press and release Cap Lock Key, and Capbit goes low.....
;* Press and release it again, and Capbit goes high....
;* Cntldown is the flag which is set and reset when you
;* press Cap Lock and then another key. Then, Cap Lock Key
;* functions as the Control Key.
;* LAMIGA,RAMIGA,and CONTROL are all flags that tell if those
;* keys are being held down. When all three are, the computer
;* will reset.
;*
;* ATparity is the 10th bit that the AT keyboard transmits. It
;* is SET if the number of DATA bits set is EVEN. Otherwise, its
;* CLEARED.
;*
;**************************************************
;bit memory locations:
.equ Capbit,42h
.equ Capdown,43h
.equ Ctrldown,44h
.equ CONTROL,45h
.equ LAMIGA,46h
.equ RAMIGA,47h
.equ ATparity,48h
.equ Make,49h
;byte memory locations:
.equ Charbad,50h
.equ Oldchar,51h
.equ Amigachar,52h
.org 0200h
start: mov tmod,#11h ;two 16 bit timers
mov tcon,#05h ;edge triggered interrupt.
mov ie,#00h ;clear all interrupts
setb ea
setb et1 ;enable timer 1
setb pt0 ;timer 0 has high priority
mov sp,#30h ;stack somewhere safe.
; set the ports for input
mov p1,#255 ;set port1 for read
clr tr1 ;make sure timers are in
clr tf1 ;reset state.
clr tr0
clr tf0
; clear out the miscellaneous flags.
clr Capdown ;Caps is up...
clr Ctrldown ;Control is up
clr Capbit ;Caps light is off.
setb CONTROL ;all reset keys are UP
setb LAMIGA
setb RAMIGA
;**** sync the controller with the Amiga. clock out
;**** ones until we receive a handshake...
sync:
mov tl1,#0 ;set up timer for 143ms
mov th1,#0
mov r1,#2
setb tr1
sync2:
jb Adat,sync2 ;wait for handshake
sync3:
jnb Adat,sync3 ;wait for end of handshake
clr tr1
;**** transmit power up key stream and end key stream.
mov a,#0FDh
acall actualtransmit
mov a,#0FEh
acall actualtransmit
;**** sync up the AT and go with it!
ATPowerup:
mov a,#0ffh ;RESET
acall SendtoAT
mov a,#0f6h ;DEFAULT
acall SendtoAT
mov a,#0edh ;NEXT DATA is FOR LIGHTS
acall SendtoAT
mov a,#2 ;NUMLOCK ON?
acall SendtoAT
mov a,#0f4h ;CLEAR BUFFER
acall SendtoAT
ljmp ATstyle ;go and parse AT keyboard
;***********************************************
;* ATgetkey
;* ATgetkey
;* ATgetkey
;*
;* ATgetkey looks at the keyboard and waits for a key to be
;* pressed. ATinkey is the actual routine that watched the logic
;* levels of Kdat and Kclk. IF the character's parity is not
;* what it is supposed to be, then the routine will attempt to
;* tell the keyboard to resend.
;*
;* When exiting from this routine, Kclock is pulled low to hold
;* off any more transmissions. You must restore it to 5 volts to
;* receive any more characters later.
;*
;*
ATgetkey:
mov r0,#11 ;number of bits
setb Kclk
ATwaitC0:
jb Kclk,ATwaitC0 ;wait for a clock pulse
dec r0 ;decrement clock bit counter
cjne r0,#10,ATnstart ;test for startbit
sjmp ATwait
ATnstart:
cjne r0,#0,ATnstop ;check for stopbit
ATwaitC1:
jnb Kclk,ATwaitC1 ;wait for clock to go high
clr Kclk ;hold off more data
mov r0,#20 ;small delay
pause: djnz r0,pause
;**** now we check to see if the parity between
;**** Bit register P (which is set if Parity of Acc is odd)
;**** is compared to the received Parity Bit.
jb p,parityodd ;test if parity of DATA is odd
parityeven:
jnb ATparity,ATerror
ret ;Okay to return. A=valid
parityodd:
jb ATparity,ATerror
ret ;Okay to return. A=valid
ATerror:
mov a,#0feh ;RESEND character
acall SendtoAT
sjmp ATgetkey ;now return to caller
ATnstop:
cjne r0,#1,ATdatab ;check for paritybit
mov c,Kdat ;error checking! (AT only)
mov ATparity,c
sjmp ATwait ;
ATdatab:
mov c,Kdat ;get data bit
rrc a ;shift it into accumulator
ATwait: jnb Kclk,ATwait ;wait for clock line to go low
sjmp ATwaitC0 ;get another bit
;**************************************************
;* AT-STYLE
;*
;* This waits for a keycode or two from the IBM and then calls
;* the appropriate transmit subroutine. The IBM keyboard sends
;* out special codes in front of and behind some scancodes. This
;* routine will chop them out before doing a lookup on the
;* code to see what to send to the AMIGA. The scancodes between
;* the IBM and the AMIGA are of course, not the same!
;*
;**************************************************
ATstyle:
acall ATgetkey ;get one scancode.
cjne a,#0e1h,ATnE1
acall ATgetkey ;(should be 14)
acall ATgetkey ;(should be 77)
acall ATgetkey ;(should be E1)
acall ATgetkey ;(should be F0)
acall ATgetkey ;(should be 14)
acall ATgetkey ;(should be F0)
acall ATgetkey ;(should be 77)
sjmp ATstyle
;PAUSE was pressed. Just ignore it.
ATnE1:
mov dptr,#ATtb1
cjne a,#0e0h,ATnE0
mov dptr,#ATtb2
acall ATgetkey
cjne a,#0f0h,ATnE0F0
acall ATgetkey
cjne a,#12h,ATnEF12
ljmp ATstyle ;(E0F012....ignore it)
ATnEF12:
cjne a,#59h,ATup ;(E0F0mk)
ljmp ATstyle ;(E0F059....ignore it)
ATnE0F0:
cjne a,#12h,ATnE012
ljmp ATstyle ;(E012....ignore it)
ATnE012:
cjne a,#59h,ATdown ;(E0mk)
ljmp ATstyle ;(E059....ignore it)
ATnE0:
cjne a,#0f0h,ATdown ;(mk)
acall ATgetkey
sjmp ATup ;(F0mk....normal key break)
;**************************************************
;* ATdown and the rest here call a lookup table to change
;* the AT scancodes into AMIGA scancodes. In the "down"
;* routine, the "make" bit is asserted. In the "up" routine
;* it is de-asserted.
;**************************************************
ATdown:
movc a,@a+dptr ;indexed into table
clr acc.7 ;clear make/break bit
acall transmit ;transmit it
ljmp ATstyle
ATup:
movc a,@a+dptr
setb acc.7 ;set make/break bit
acall transmit ;transmit it
ljmp ATstyle
;**************************************************
;* SendtoAT is the subroutine that sends special codes
;* to the keyboard from the controller. Codes include
;* the command to reset (FF) or the command to change
;* the lights (ED). It is advisable to keep the timing
;* very close to how I have it done in this routine.
;**************************************************
SendtoAT:
setb Kclk
clr Kdat
mov r0,#8
Send4: jb Kclk,Send4 ;data bit
mov c,acc.0
mov Kdat,c
rr a
Send5: jnb Kclk,Send5 ;data bit
dec r0
cjne r0,#0,Send4
mov c,p
cpl c
Send6: jb Kclk,Send6 ;parity bit
mov Kdat,c
Send7: jnb Kclk,Send7 ;parity bit
Send77: jb Kclk,Send77 ;stop bit
setb Kdat
Send78: jnb Kclk,Send78 ;stop bit
Send79: jb Kclk,Send79
Send7a: jnb Kclk,Send7a
mov r0,#8 ;small delay
Send8: djnz r0,Send8
clr Kclk ;drive clock low
mov r0,#20 ;long delay
Send9: djnz r0,Send9
setb Kclk
acall ATgetkey ;should check if response isbad.
ret ;who cares if it is? not me!
;**************************************************
;*
;* TRANSMIT first does some checking to take out repeating
;* keys and does the conversion on the Caps Lock Key and
;* then calls Actualtransmit.
;*
;**************************************************
dontrans: ;jumps back if key is already
pop acc ;held down.
ret
transmit:
cjne a,Oldchar,transok
ret
transok:
cjne a,#62h,transok2 ;jump if not CapsLock=down
mov Oldchar,a
setb Capdown ;set the flags for later
ret
transok2:
cjne a,#0e2h,transok3;jump if not CapsLock=up
mov a,Oldchar ;see if Caps was just down
cjne a,#62h,transok4 ;if not, then it was a control
XTcap:
clr Capdown ;clear flag
cpl Capbit ;toggle down/up-ness of Caplock
mov a,#62h
mov c,Capbit
cpl c
mov acc.7,c
acall actualtransmit ;(Caps to Amiga!)
mov a,#0edh ;set lights on next byte.
acall SendtoAT
mov a,#2 ;numlock on
mov c,Capbit
mov acc.2,c
acall SendtoAT ;maybe capslock light
skiplights:
ret
transok4:
clr CtrlDown ;This sends out a Control Up.
clr Capdown ;Caps lock is done functioning as Ctl
mov a,#63h ;Control Key
setb acc.7 ;break bit set.
acall actualtransmit ;send to Amiga.
ret
transok3:
mov Oldchar,a
jnb Capdown,noControl
jb CtrlDown,noControl
setb CtrlDown ;Caps lock is beginning to function
mov a,#63h ;as the Control Key.
acall actualtransmit ;send Control Down to Amiga
mov a,Oldchar ;now send the actual key
noControl: ;its not a controlled key
mov c,acc.7 ;c=make/break bit
mov Make,c ;will be set if key up
clr acc.7 ;test for key only. NO make/break
cjne a,#0eh,noMup ;special key mouse up
jnb Make,kmupdown
kmupup:
mov a,#0cch ;cursor up break
acall actualtransmit
acall Smalldelay
mov a,#0e7h ;right amiga break
acall actualtransmit
ret
kmupdown:
mov a,#67h ;amiga make
acall actualtransmit
acall Smalldelay
mov a,#4ch ;cursor up make
acall actualtransmit
ret
noMup:
cjne a,#1ch,noMdown ;special key mouse down
jnb Make,kmdowndown
kmdownup:
mov a,#0cdh ;cursor down break
acall actualtransmit
mov a,#0e7h ;amiga break
acall Smalldelay
acall actualtransmit
ret
kmdowndown:
mov a,#67h ;amiga make
acall actualtransmit
acall Smalldelay ;cursor down make
mov a,#4dh
acall actualtransmit
ret
noMdown:
cjne a,#2ch,noMleft ;special key mouse left
jnb Make,kmleftdown
kmleftup:
mov a,#0cfh ;cursor left break
acall actualtransmit
acall Smalldelay ;amiga break
mov a,#0e7h
acall actualtransmit
ret
kmleftdown:
mov a,#67h ;amiga make
acall actualtransmit
acall Smalldelay
mov a,#4fh ;cursor left make
acall actualtransmit
ret
noMleft: ;special key mouse right
cjne a,#47h,notspecial
jnb Make,kmrhtdown
kmrhtup:
mov a,#0ceh ;cursor right break
acall actualtransmit
acall Smalldelay
mov a,#0e7h ;amiga break
acall actualtransmit
ret
kmrhtdown:
mov a,#67h ;amiga make
acall actualtransmit
acall Smalldelay
mov a,#04eh ;cursor right make
acall actualtransmit
ret
Smalldelay:
mov th0,#0
mov tl0,#0
clr tf0
setb tr0
small1: jnb tf0,small1
clr tf0
clr tr0
ret
notspecial:
mov a,Oldchar
acall actualtransmit ;transmit the keycode
mov a,Oldchar ;get back same keycode, in A.
mov c,acc.7 ;put make/break bit in Make
mov Make,c
clr acc.7 ;start testing for reset keys
cjne a,#63h,nrset1 ;held down
mov c,Make
mov CONTROL,c
sjmp trset
nrset1: cjne a,#66h,nrset2
mov c,Make
mov LAMIGA,c
sjmp trset
nrset2: cjne a,#67h,trset
mov c,Make
mov RAMIGA,c
trset: jnb CONTROL,maybefree ;if bit set, this key is up
jb CtrlDown,maybefree ;if bit set, this key is down
sjmp free
maybefree:
jb LAMIGA,free ;ditto
jb RAMIGA,free ;ditto
sjmp resetwarn ;OOPS! They are all down!
free: ret
resetwarn:
clr tf0
mov a,78h
mov r1,#2 ;set up timer 0 watchdog
mov tl0,#0
mov th0,#0
cpl a ;invert, don't know why.
mov r0,#8
wr1:
rl a
mov c,acc.7
mov Adat,c
mov b,#8
wr2:
djnz b,wr2 ; transmit it.
clr Aclk
mov b,#8
wr3:
djnz b,wr3
setb Aclk
mov b,#10
wr4:
djnz b,wr4
djnz r0,wr1
setb Adat
setb tr0 ;start watchdog
wr5:
jnb Adat,caught1
jnb tf0,wr5
clr tf0
djnz r1,wr5
sjmp Hardreset
caught1:
clr tr0
clr tf0
mov a,78h
mov r1,#4
mov tl0,#0
mov th0,#0
cpl a
mov r0,#8
wr11:
rl a
mov c,acc.7
mov Adat,c
mov b,#8
wr22:
djnz b,wr22
clr Aclk
mov b,#8
wr33:
djnz b,wr33
setb Aclk
mov b,#10
wr44:
djnz b,wr44
djnz r0,wr11
setb Adat
setb tr0 ;start watchdog
wr55:
jnb Adat,caught2
jnb tf0,wr55
clr tf0
djnz r1,wr55
sjmp Hardreset
caught2:
hold: jnb Adat,hold
Hardreset:
clr tr0
clr tf0
clr Areset
clr Aclk ;clear both lines for A500/A1000
mov r1,#15 ;clock should go low for over 500ms
mov th0,#0 ;timer 1 will overflow repeatedly
mov tl0,#0
setb tr0
hsloop:
jnb tf0,hsloop ;wait for overflow flag
clr tf0 ;clear it again
djnz r1,hsloop
clr tf0
clr tr0 ;stop the timer
ljmp start
;**************************************************
;*
;* ActualTransmit sends the character out to the Amiga and waits
;* for an acknowledge handshake. If it does not receive one in
;* 143 ms, then it clocks out 1's on the data line until it
;* receives the acknowledge. If the Amiga is not connected up,
;* then it will hang here. The handshake is that the AMIGA
;* drives the clock line low.
;*
;* The loops with register B are for timing delays.
;* There should be about 20usec between when the Data line is
;* set, the Clock line is driven low, and the Clock line
;* is driven high.
;*
;**************************************************
actualtransmit:
mov Amigachar,a ;set the character to transmit
mov r0,#05 ;do a small delay
dly:
mov b,#0
delay: djnz b,delay
djnz r0,dly
actual2:
mov a,Amigachar ;restore it
clr Charbad ;character is not bad yet
mov r1,#2 ;set up timer 0 watchdog
mov tl1,#0
mov th1,#0
cpl a ;invert, don't know why.
mov r0,#8
f: rl a
mov c,acc.7
mov Adat,c
mov b,#8
g: djnz b,g ; transmit it.
clr Aclk
mov b,#8
h: djnz b,h
setb Aclk
mov b,#10
i: djnz b,i
djnz r0,f
setb Adat
setb tr1 ;start watchdog
waitshake:
jb Adat,waitshake
clr tr1 ;stop watchdog
gotit: jnb Adat,gotit
ret
timer1int:
djnz r1,t3 ;we wait for 143 ms.
mov r1,#2
setb Charbad ;flag to resend the character
clr Adat ;1 on the data line
mov b,#8
tt1: djnz b,tt1 ;wait for it
clr Aclk ;clock asserted
mov b,#8 ;sync up the controller to the
tt2: djnz b,tt2 ;amiga
setb Aclk
mov b,#10
tt3: djnz b,tt3
setb Adat
t3: reti ;return and send again.
ATtb1:
.db 0
.db 58h ;F9
.db 0
.db 54h ;F5
.db 52h ;F3
.db 50h ;F1
.db 51h ;F2
.db 63h ;F12=CTRL (charles)
.db 0
.db 59h ;F10
.db 57h ;F8
.db 55h ;F6
.db 53h ;F4
.db 42h ;TAB
.db 00h ;~
.db 0
.db 0
.db 64h ;Left ALT
.db 60h ;Left SHIFT
.db 0
.db 66h ;Left Ctrl=Left AMIGA
.db 10h ;Q
.db 01h ;1
.db 0
.db 0
.db 0
.db 31h ;Z
.db 21h ;S
.db 20h ;A
.db 11h ;W
.db 02h ;2
.db 0
.db 0
.db 33h ;C
.db 32h ;X
.db 22h ;D
.db 12h ;E
.db 04h ;4
.db 03h ;3
.db 0
.db 0
.db 40h ;SPACE
.db 34h ;V
.db 23h ;F
.db 14h ;T
.db 13h ;R
.db 05h ;5
.db 0
.db 0
.db 36h ;N
.db 35h ;B
.db 25h ;H
.db 24h ;G
.db 15h ;Y
.db 06h ;6
.db 0
.db 0
.db 0
.db 37h ;M
.db 26h ;J
.db 16h ;U
.db 07h ;7
.db 08h ;8
.db 0
.db 0
.db 38h ;<
.db 27h ;K
.db 17h ;I
.db 18h ;O
.db 0Ah ;0
.db 09h ;9
.db 0
.db 0
.db 39h ;>
.db 3ah ;/
.db 28h ;L
.db 29h ; ';'
.db 19h ;P
.db 0bh ;-
.db 0
.db 0
.db 0
.db 2ah ;'
.db 0
.db 1ah ;[
.db 0ch ;=
.db 0
.db 0
.db 62h ;CAPS LOCK?
.db 61h ;Right SHIFT
.db 44h ;RETURN
.db 1bh ;]
.db 0
.db 2bh ; µ ( put 2b instead d, Charles)
.db 0
.db 0
.db 0
.db 30h ; < (add by Charles Da Costa)
.rs 4
.db 41h ;Back SPACE
.db 0
.db 0
.db 1dh ;1 keypad
.db 0
.db 2dh ;4 keypad
.db 3dh ;7 keypad
.db 0
.db 0
.db 0
.db 0fh ;0 keypad
.db 3ch ;dot keypad
.db 1eh ;2 keypad
.db 2eh ;5 keypad
.db 2fh ;6 keypad
.db 3eh ;8 keypad
.db 45h ;ESCAPE!
.db 5ah ;Number Lock=( (instead 63 Charles)
.db 32h ;F11=x (instead 5a Charles)
.db 5eh ;+ keypad
.db 1fh ;3 keypad
.db 4ah ;- keypad
.db 5dh ;* keypad
.db 3fh ;9 keypad
.db 67h ;scroll Lock=Right AMIGA
.db 0
ATtb2:
.rs 3
.db 56h ;F7
.db 66h ;print screen=Left Amiga
.rs 11
.db 0
.db 65h ;Right ALT
.db 0
.db 0
.db 67h ;Right CTL=RIGHT AMIGA
.rs 11
.rs 10h
.rs 10h
.rs 10
.db 5ch ;/key, supposedly
.rs 5
.rs 10
.db 43h ;Numeric Enter
.rs 5
.rs 9
.db 1ch ;End=Mouse down
.db 0
.db 4fh ;Cursor Left
.db 0eh ;Home=Mouse up
.db 0
.db 0
.db 63h ;MACRO key=control
.db 2ch ;Insert=Mouse Left
.db 46h ;Delete
.db 4dh ;Cursor Down
.db 0
.db 4eh ;Cursor Right
.db 4ch ;Cursor Up
.rs 4
.db 5fh ;Page Down=Help
.db 0
.db 66h ;print screen=LEFT AMIGA
.db 47h ;Page up=mouse right
.db 40h ;Break=Space?
.db 0
.end 0